diff options
| author | Adrien Hopkins <[email protected]> | 2022-08-02 13:13:27 -0500 |
|---|---|---|
| committer | Adrien Hopkins <[email protected]> | 2022-08-02 13:13:27 -0500 |
| commit | c21ee41b206db79b2157d8743b0473a094448dfb (patch) | |
| tree | fac1a595e451c0b32ceedfe4fb70855270456377 /src/routes/[username] | |
| parent | 3b216dd6c170a7d71d21a391098c554008c8bdb4 (diff) | |
| parent | 05f5001fc7d325e31d9c777be11343604c72fbfd (diff) | |
| download | coinos-ui-c21ee41b206db79b2157d8743b0473a094448dfb.tar.gz coinos-ui-c21ee41b206db79b2157d8743b0473a094448dfb.zip | |
Merge branch 'master' into i18n
Diffstat (limited to 'src/routes/[username]')
| -rw-r--r-- | src/routes/[username]/customers.svelte | 5 | ||||
| -rw-r--r-- | src/routes/[username]/dashboard.svelte | 5 | ||||
| -rw-r--r-- | src/routes/[username]/index.js | 14 | ||||
| -rw-r--r-- | src/routes/[username]/index.svelte | 95 | ||||
| -rw-r--r-- | src/routes/[username]/receive.svelte | 187 | ||||
| -rw-r--r-- | src/routes/[username]/settings.svelte | 5 | ||||
| -rw-r--r-- | src/routes/[username]/transactions.svelte | 5 |
7 files changed, 316 insertions, 0 deletions
diff --git a/src/routes/[username]/customers.svelte b/src/routes/[username]/customers.svelte new file mode 100644 index 00000000..1935b156 --- /dev/null +++ b/src/routes/[username]/customers.svelte @@ -0,0 +1,5 @@ +<script> + import { AppHeader } from '$comp'; +</script> + +<AppHeader /> diff --git a/src/routes/[username]/dashboard.svelte b/src/routes/[username]/dashboard.svelte new file mode 100644 index 00000000..1935b156 --- /dev/null +++ b/src/routes/[username]/dashboard.svelte @@ -0,0 +1,5 @@ +<script> + import { AppHeader } from '$comp'; +</script> + +<AppHeader /> diff --git a/src/routes/[username]/index.js b/src/routes/[username]/index.js new file mode 100644 index 00000000..5de1316f --- /dev/null +++ b/src/routes/[username]/index.js @@ -0,0 +1,14 @@ +import { get } from '$lib/utils'; + +export async function GET({ params }) { + let { username } = params; + let body; + + try { + body = await get(`/users/${username}`); + } catch (e) { + body = {}; + } + + return { body }; +} diff --git a/src/routes/[username]/index.svelte b/src/routes/[username]/index.svelte new file mode 100644 index 00000000..6002efdc --- /dev/null +++ b/src/routes/[username]/index.svelte @@ -0,0 +1,95 @@ +<script> + import { toast } from '@zerodevx/svelte-toast'; + import { browser } from '$app/env'; + import { onMount } from 'svelte'; + import { AppHeader, Icon, PageNotFound } from '$comp'; + import { user } from '$lib/store'; + import { copy } from '$lib/utils'; + export let username; + + let lightningAddress = `${username}@coinos.io`; + + onMount(async () => { + if (browser) { + let { default: QRCodeStyling } = await import('qr-code-styling'); + const qrCode = new QRCodeStyling({ + width: window.screen.width < 640 ? 250 : 300, + type: 'svg', + data: 'add static qr here', + image: '/images/invoice.svg', + backgroundOptions: { + color: 'rgba(0, 0, 0, 0)' + }, + dotsOptions: { + type: 'rounded' + }, + imageOptions: { + hideBackgroundDots: false + } + }); + + qrCode.append(document.getElementById('qr')); + } + }); + + let followed = false; + + let qrSkeleton = true; + setTimeout(() => (qrSkeleton = false), 100); + + const handleCopy = () => { + copy(lightningAddress); + toast.push('Copied!', { + theme: { + '--toastBarBackground': '#2F855A' + } + }); + }; +</script> + +{#if username} + <AppHeader avatarPosition="left-[calc(15vw-48px)]" /> + + <div class="flex xl:block justify-center items-center my-20 px-3"> + <div class="space-y-10 xl:space-y-0"> + <div class="xl:ml-[calc(15vw-48px)] space-y-2 w-full md:w-72"> + <h1 class="text-3xl font-bold">{username}</h1> + + <p class="text-secondary">Address goes here</p> + + <button + class="border rounded-full py-2 w-28 font-semibold flex justify-center items-center text-sm" + on:click={() => (followed = !followed)} + ><Icon icon={followed ? 'minus' : 'plus'} style="mr-1" /> + {followed ? 'Remove' : 'Follow'} + </button> + </div> + + <div class="space-y-5 static xl:absolute top-[255px] left-[calc(50vw-150px)]"> + <div + id="qr" + class="border border-lightgrey rounded-3xl flex md:p-5 justify-center items-center relative" + > + <div + class="z-100 h-[300px] md:h-[342px] w-[250px] md:w-[342px] animate-pulse absolute top-0 left-0 bg-gray-400 rounded-3xl {qrSkeleton + ? 'block' + : 'hidden'}" + /> + </div> + + <p class="text-secondary text-center font-semibold">Scan to pay with Bitcoin</p> + + <div + class="bg-primary font-semibold rounded-xl text-sm py-2 px-3 flex flex-wrap justify-center items-center" + > + <span>{lightningAddress}</span> + <button on:click={handleCopy}> + <Icon icon="copy" style="ml-2" /> + </button> + </div> + </div> + </div> + </div> +{:else} + <PageNotFound /> +{/if} diff --git a/src/routes/[username]/receive.svelte b/src/routes/[username]/receive.svelte new file mode 100644 index 00000000..50fddbed --- /dev/null +++ b/src/routes/[username]/receive.svelte @@ -0,0 +1,187 @@ +<script> + // in the future we will want to allow users to set their fiat currency in the settings + import { AppHeader, Icon } from '$comp'; + import { goto } from '$app/navigation'; + import { invoiceAmount, invoiceAmountFiat, rate, user } from '$lib/store'; + import { post } from '$lib/utils'; + import { page } from '$app/stores'; + + let useFiat = true; + let amountFiat = 0; + let amountSats = 0; + let message = ''; + + $: amount = useFiat ? Math.round(amountFiat / ($rate / 100000000)) : amountSats; + + $: $invoiceAmount = parseInt(amountSats === 0 ? amountFiat / ($rate / 100000000) : amountSats); + $: $invoiceAmountFiat = parseInt( + amountFiat === 0 ? amountSats * ($rate / 100000000) : amountFiat + ); + $: amountSatsFormatted = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format( + amountSats + ); + + $: amountFiatConverted = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD' + }).format(amountSats * ($rate / 100000000)); + + $: amountSatsConverted = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format( + amountFiat / ($rate / 100000000) + ); + + const numPad = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', '<']; + + const handleInput = (value) => { + if (message) { + message = ''; + } + if (useFiat) { + if (amountFiat === 0 && value !== '.' && value !== '<' && value !== '0') { + amountFiat = value; + } else if ((amountFiat === 0 || amountFiat === '0') && value === '0') { + return; + } else if (amountFiat === 0 && value === '.') { + amountFiat = '0.'; + } else if (amountFiat !== 0 && amountFiat.includes('.') && value === '.') { + return; + } else if (value === '<') { + if (amountFiat !== 0) { + amountFiat = amountFiat.slice(0, amountFiat.length - 1); + if (amountFiat.length === 0) { + amountFiat = 0; + amountSats = 0; + } + } + } else if (value !== '.' && value !== '<' && parseInt(amountFiat + value) > $rate) { + message = 'Please enter an amount less than 1 bitcoin.'; + } else if (amountFiat !== 0 && amountFiat.match(/\.../)) { + return; + } else { + amountFiat = amountFiat + value; + } + } else { + if (value === '.') { + return; + } else if (amountSats === 0 && value !== '<' && value !== '0') { + amountSats = value; + } else if (value === '<') { + if (amountSats !== 0) { + amountSats = amountSats.slice(0, amountSats.length - 1); + if (amountSats.length === 0) { + amountSats = 0; + amountFiat = 0; + } + } + } else if (value !== '<' && parseInt(amountSats + value) > 100000000) { + message = 'Please enter an amount less than 1 bitcoin.'; + } else { + amountSats = amountSats + value; + } + } + }; + + let submit = async () => { + let { id } = await post('/invoice', { amount, rate: $rate, username: $page.params.username }); + goto(`/invoice/${id}`); + }; +</script> + +{#if $user} + <AppHeader /> + + <div class="flex justify-center items-center mt-20 mb-3 px-3"> + {#if $rate} + <div class="space-y-5"> + <!-- amounts --> + <div class="text-center"> + <div class="text-5xl md:text-6xl font-semibold tracking-widest mb-1"> + {useFiat ? `$${amountFiat}` : amountSatsFormatted}<span + class="tracking-normal text-base font-normal">{useFiat ? 'USD' : 'SATS'}</span + > + </div> + <span class="text-secondary mr-1" + >{useFiat ? `${amountSatsConverted} SATS` : `${amountFiatConverted} USD`}</span + > + <button + on:click={() => { + if (useFiat) { + amountSats = (amountFiat / ($rate / 100000000)).toFixed(0).toString(); + } else { + amountFiat = + (amountSats * ($rate / 100000000)).toFixed(2) > 0.0 + ? (amountSats * ($rate / 100000000)).toFixed(2).toString() + : 0; + } + useFiat = !useFiat; + }}><Icon icon="swap" style="inline" /></button + > + </div> + + <!-- error message --> + {#if message} + <div + class="text-orange-500 text-sm text-center font-bold bg-primary p-2 rounded-xl flex justify-center items-center space-x-1" + > + <Icon icon="info" style="w-5" /> + <p>{message}</p> + </div> + {/if} + + <!-- numpad --> + <div class="grid grid-cols-3 gap-2 w-full md:w-[300px] mx-auto"> + {#each numPad as value} + {#if value === '<'} + <button + class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white flex justify-center items-center" + on:click={() => handleInput(value)} + > + <svg + class="w-5" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M15 19L8 12L15 5" + stroke="currentColor" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + /> + </svg> + </button> + {:else} + <button + class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white" + on:click={() => handleInput(value)}>{value}</button + > + {/if} + {/each} + </div> + + <!-- buttons --> + <div class="space-y-3 w-full md:w-[300px] mx-auto"> + <button + class="bg-black text-white rounded-xl w-full h-[48px] flex justify-center items-center font-semibold text-sm {$invoiceAmount === + 0 + ? 'opacity-50' + : 'opacity-100'}" + on:click={submit} + disabled={$invoiceAmount === 0}><Icon icon="qr" style="mr-2" /> Show QR</button + > + <button + class="bg-primary rounded-xl w-full h-[48px] flex justify-center items-center font-semibold text-sm" + disabled={true}><Icon icon="send" style="mr-2" /> Send Invoice</button + > + </div> + </div> + {:else} + <div + class="w-full md:w-[300px] h-[475px] md:h-[485px] animate-pulse bg-gray-400 rounded-xl" + /> + {/if} + </div> +{/if} diff --git a/src/routes/[username]/settings.svelte b/src/routes/[username]/settings.svelte new file mode 100644 index 00000000..1935b156 --- /dev/null +++ b/src/routes/[username]/settings.svelte @@ -0,0 +1,5 @@ +<script> + import { AppHeader } from '$comp'; +</script> + +<AppHeader /> diff --git a/src/routes/[username]/transactions.svelte b/src/routes/[username]/transactions.svelte new file mode 100644 index 00000000..1935b156 --- /dev/null +++ b/src/routes/[username]/transactions.svelte @@ -0,0 +1,5 @@ +<script> + import { AppHeader } from '$comp'; +</script> + +<AppHeader /> |
